package com.space.feign;

import feign.Feign;
import feign.Request;
import feign.Retryer;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;

/**
 * @author: ggy
 * @date: 2021/5/15 20:47
 * @e-mail: guogy15@chinaunicom.cn implements BeanDefinitionRegistryPostProcessor
 */
//@Configuration
public class RegisterFeignConfig implements BeanDefinitionRegistryPostProcessor {
    /**
     * 注册bean
     **/
    private void registerBean(BeanDefinitionRegistry registry) throws IOException, ClassNotFoundException {

        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
        Resource[] resources = pathMatchingResourcePatternResolver.getResources("classpath*:com/space/feign/i/*.class");
        ClassLoader loader = ClassLoader.getSystemClassLoader();

        for (Resource resource : resources) {
            MetadataReader reader = cachingMetadataReaderFactory.getMetadataReader(resource);
            String className = reader.getClassMetadata().getClassName();
            Class<?> aClass = loader.loadClass(className);
            RootBeanDefinition bean = new RootBeanDefinition(FeignFactoryBean.class);
            bean.getConstructorArgumentValues().addGenericArgumentValue(aClass);
            registry.registerBeanDefinition(aClass.getSimpleName(), bean);
        }
    }

    static class FeignFactoryBean<T> implements FactoryBean<T> {
        @Value("${provider.url}")
        private String providerUrl;

        Class<T> t;

        FeignFactoryBean(Class<T> t) {
            this.t = t;
        }

        @Override
        public T getObject() throws Exception {
            return Feign.builder()
                    .encoder(new GsonEncoder())
                    .decoder(new GsonDecoder())
                    .options(new Request.Options(1000, 3500))
                    .retryer(new Retryer.Default(5000, 5000, 3))
                    .target(t, providerUrl);
        }

        @Override
        public Class<?> getObjectType() {
            return t;
        }

        @Override
        public boolean isSingleton() {
            return true;
        }
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        try {
            this.registerBean(beanDefinitionRegistry);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}
